#pragma once
#include <unordered_set>
#include "Common.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"

using namespace myLog;

//为了防止有人乱用(命令是服务器在执行)，所以要限制，使用白名单
class Command{
public:
    Command(){
        _white_list_cmds.insert("ls");
        _white_list_cmds.insert("ls -l");
        _white_list_cmds.insert("ls -la");
        _white_list_cmds.insert("ls -lh");
        _white_list_cmds.insert("pwd");
        _white_list_cmds.insert("cd ~");
        _white_list_cmds.insert("cd -");
        _white_list_cmds.insert("du -sh *");
        _white_list_cmds.insert("uname -a");
        _white_list_cmds.insert("uname -r");
        _white_list_cmds.insert("ulimit -a");
        _white_list_cmds.insert("hostname");
        _white_list_cmds.insert("hostnamectl");
        _white_list_cmds.insert("cat /etc/os-release");
        _white_list_cmds.insert("cat /proc/version");
        _white_list_cmds.insert("uptime");
        _white_list_cmds.insert("who");
    }
    ~Command(){}

    std::string Execute(std::string cmd, const InetAddr& addr){
        std::string who = addr.GetFormatStr();
        if(!IsSafeCmd(cmd)){
            LOG(LogLevel::INFO) << who << " : " << "cmd illegal";
            std::string illegal = who + " : " + "your cmd is illegal";
            return illegal;
        }
        else{
            //使用popen操作，系统会创建子进程 + 管道，返回管道读端。
            //子进程执行完后，父进程可以从读端读取
            FILE* FP = popen(cmd.c_str(), "r");
            if(!FP){
                LOG(LogLevel::INFO) << who << " : " << "cmd cannot be found";
                std::string none = who + " : " + "your cmd connot be found";
                return none;
            }
            char buffer[1024] = {0};
            std::string result;
            while(fgets(buffer, sizeof(buffer) - 1, FP)){
                result += buffer;
                memset(buffer, 0, sizeof(buffer));
            }
            who += ": result is \n";
            return who + result;
        }
    }

    bool IsSafeCmd(std::string cmd){
        auto it = _white_list_cmds.find(cmd);
        return it != _white_list_cmds.end();
    }

private:
    std::unordered_set<std::string> _white_list_cmds;    
};